package com.ssy.lingxi.contract.serviceimpl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.ssy.lingxi.after.sale.api.model.vo.response.ReturnGoodsInfoVO;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.contract.api.model.constant.ContractOrderTypeEnum;
import com.ssy.lingxi.contract.entity.ApplyAmountOrderDO;
import com.ssy.lingxi.contract.entity.ApplyAmountOrderDetailDO;
import com.ssy.lingxi.contract.entity.ContractExecuteInfoDO;
import com.ssy.lingxi.contract.model.constant.ApplyAmountOrderStatusEnum;
import com.ssy.lingxi.contract.model.constant.CommonBooleanEnum;
import com.ssy.lingxi.contract.model.vo.applyamount.request.ApplyAmountOrderDetailPageVO;
import com.ssy.lingxi.contract.model.vo.applyamount.request.ApplyAmountOrderSaveDetailVO;
import com.ssy.lingxi.contract.model.vo.applyamount.request.UpdateApplyAmountVO;
import com.ssy.lingxi.contract.model.vo.applyamount.response.ApplyAmountOrderDetailQueryVO;
import com.ssy.lingxi.contract.model.vo.applyamount.response.ApplyAmountOrderDetailVO;
import com.ssy.lingxi.contract.model.vo.execute.request.ContractExecutePayDetailVO;
import com.ssy.lingxi.contract.repository.ApplyAmountOrderDetailRepository;
import com.ssy.lingxi.contract.repository.ApplyAmountOrderRepository;
import com.ssy.lingxi.contract.service.IApplyAmountOrderDetailService;
import com.ssy.lingxi.contract.service.IContractExecuteInfoService;
import com.ssy.lingxi.contract.service.IFeignService;
import com.ssy.lingxi.order.api.model.vo.response.OrderAfterSaleStatusVO;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 请款单明细接口实现
 * @author 伍将
 * @date 2021/3/10
 * @version 2.0.0
 */
@Service
public class ApplyAmountOrderDetailServiceImpl implements IApplyAmountOrderDetailService {

    @Resource
    private ApplyAmountOrderDetailRepository repository;

    @Resource
    private IContractExecuteInfoService executeService;

    @Resource
    private ApplyAmountOrderRepository orderRepository;

    @Resource
    private IFeignService feignService;

    /**
     * 分页查询请款单明细
     * @author 伍将
     * @date 2021/3/10
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ApplyAmountOrderDetailQueryVO>> pageList(ApplyAmountOrderDetailPageVO pageVO) {
        // 组装查询条件
        Specification<ApplyAmountOrderDetailDO> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("applyId").as(Long.class), pageVO.getApplyId()));

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").ascending());

        Page<ApplyAmountOrderDetailDO> result = repository.findAll(spec, page);

        // 查询合同执行请款
        List<ContractExecuteInfoDO> executeList = null;
        if (result.getContent().size() > 0) {
            List<Long> idList = result.getContent().stream().map(ApplyAmountOrderDetailDO::getExecuteId).collect(Collectors.toList());
            executeList = executeService.getListById(idList);
        }
        List<ContractExecuteInfoDO> finalExecuteList = executeList;
        List<Long> orderIds=new ArrayList<>();
        List<Long> returnGoodsIds=new ArrayList<>();
        List<ApplyAmountOrderDetailQueryVO> resultList = result.getContent().stream().map(o -> {
            ApplyAmountOrderDetailQueryVO entity = new ApplyAmountOrderDetailQueryVO();
            entity.setId(o.getId());
            entity.setExecuteId(o.getExecuteId());
            ContractExecuteInfoDO executeEntity = (null == finalExecuteList ? null : finalExecuteList.stream().filter(e -> e.getId().equals(o.getExecuteId())).findFirst().orElse(null));
            if (null != executeEntity) {
                entity.setOrderId(executeEntity.getOrderId());
                entity.setOrderNO(executeEntity.getOrderNO());
                entity.setOrderAbstract(executeEntity.getOrderAbstract());
                entity.setOrderType(executeEntity.getOrderType());
                entity.setOrderTypeName(ContractOrderTypeEnum.getMessage(executeEntity.getOrderType()));
                entity.setOrderTime(DateUtil.format(DateUtil.date(executeEntity.getOrderTime()), "yyyy-MM-dd HH:mm"));
                entity.setOrderAmount(executeEntity.getOrderAmount());
                entity.setIsHasTax(executeEntity.getIsHasTax());
                entity.setIsHasTaxName(CommonBooleanEnum.getMessage(executeEntity.getIsHasTax()));
                entity.setTaxRate(executeEntity.getTaxRate());
                entity.setPayAmount(executeEntity.getPayAmount());
                entity.setUnPayApplyAmount(executeEntity.getUnPayApplyAmount());
                entity.setApplyAmount(o.getApplyAmount());
                if(ContractOrderTypeEnum.ORDER.getCode().equals(executeEntity.getOrderType())){
                    orderIds.add(executeEntity.getOrderId());
                }else if(ContractOrderTypeEnum.RETURN_GOODS.getCode().equals(executeEntity.getOrderType())){
                    returnGoodsIds.add(executeEntity.getOrderId());
                }
            }
            return entity;
        }).collect(Collectors.toList());
        //填充订单状态
        if(orderIds.size()>0){
            //feign order-service
            List<OrderAfterSaleStatusVO> orderStateList = feignService.getOrderStateList(orderIds);
            if(CollectionUtil.isNotEmpty(orderStateList)){
                resultList.forEach(o -> orderStateList.forEach(g ->{
                    if(g.getOrderId().equals(o.getOrderId())&&g.getOrderNo().equals(o.getOrderNO())){
                        //填充退款单状态
                        o.setStatusName(g.getOuterStatusName());
                    }
                }));
            }
        }
        //填充退货订单状态
        if(returnGoodsIds.size()>0){
            //feign after-sale-service
            List<ReturnGoodsInfoVO> returnGoodsInfoList= feignService.getReturnGoodsInfoListByIds(returnGoodsIds);
            if(CollectionUtil.isNotEmpty(returnGoodsInfoList)){
                resultList.forEach(o -> returnGoodsInfoList.forEach(g ->{
                    if(g.getReturnId().equals(o.getOrderId())&&g.getApplyNo().equals(o.getOrderNO())){
                        //填充退款单状态
                        o.setStatusName(g.getOuterStatusName());
                    }
                }));
            }
        }
        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    /**
     * 删除请款单明细
     * @author 伍将
     * @date 2021/3/10
     * @param applyId: 请款单id
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> delete(Long applyId) {

        // 查询需要还原的合同执行情况
        List<ApplyAmountOrderDetailDO> oldList = repository.findAllByApplyId(applyId);

        // 还原合同执行情况：已请款待付款
        List<UpdateApplyAmountVO> updateVOList = oldList.stream().map(o -> {
            UpdateApplyAmountVO updateVO = new UpdateApplyAmountVO();
            updateVO.setExecuteId(o.getExecuteId());
            updateVO.setApplyAmount(-o.getApplyAmount());
            return updateVO;
        }).collect(Collectors.toList());
        executeService.updateApplyAmount(updateVOList);

        // 删除请款明细
        repository.deleteAllByApplyId(applyId);

        return Wrapper.success();
    }

    /**
     * 保存请款明细
     * @author 伍将
     * @date 2021/3/11
     * @param detailList:
     * @param contractId:
     * @param applyId:
     * @param payPlanId:
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> save(List<ApplyAmountOrderSaveDetailVO> detailList, Long contractId, Long applyId, Long payPlanId) {

        // 查询旧数据
        List<ApplyAmountOrderDetailDO> oldList = repository.findAllByApplyId(applyId);

        // 如果存在旧数据，进行匹配删除
        if (oldList.size() > 0) {
            List<ApplyAmountOrderDetailDO> delList = oldList.stream().filter(o ->
                    !detailList.stream().map(ApplyAmountOrderSaveDetailVO::getId)
                            .collect(Collectors.toList())
                            .contains(o.getId()))
                    .collect(Collectors.toList());

            // 删除旧数据
            repository.deleteAll(delList);
        }

        // 组装需要还原的合同执行请款数据
        List<UpdateApplyAmountVO> updateVOList = new ArrayList<>();
        // 组装旧数据，申请款为负数，代表需要还原值
        oldList.forEach(item -> {
            UpdateApplyAmountVO updateVO = new UpdateApplyAmountVO();
            updateVO.setExecuteId(item.getExecuteId());
            updateVO.setApplyAmount(-item.getApplyAmount());
            updateVOList.add(updateVO);
        });
        // 组装新数据，申请款累加，代表需要最终还原值
        detailList.forEach(item -> {
            UpdateApplyAmountVO updateVO = new UpdateApplyAmountVO();
            updateVO.setExecuteId(item.getExecuteId());
            // 同一执行请款合并为一条
            UpdateApplyAmountVO oldEntity = updateVOList.stream().filter(o -> o.getExecuteId().equals(item.getExecuteId())).findFirst().orElse(null);
            if (oldEntity != null) {
                oldEntity.setApplyAmount(oldEntity.getApplyAmount() + item.getApplyAmount());
            } else {
                updateVO.setApplyAmount(item.getApplyAmount());
                updateVOList.add(updateVO);
            }
        });
        // 还原合同执行情况：已请款待付款
        executeService.updateApplyAmount(updateVOList);

        // 组装新增/更新数据
        List<ApplyAmountOrderDetailDO> addList = detailList.stream().map(o -> {
            ApplyAmountOrderDetailDO entity = new ApplyAmountOrderDetailDO();
            entity.setId(o.getId());
            entity.setApplyId(applyId);
            entity.setExecuteId(o.getExecuteId());
            entity.setContractId(contractId);
            entity.setPayPlanId(payPlanId);
            entity.setApplyAmount(o.getApplyAmount());
            return entity;
        }).collect(Collectors.toList());
        repository.saveAll(addList);

        return Wrapper.success();
    }

    @Override
    public Wrapper<List<ApplyAmountOrderDetailVO>> payDetailList(UserLoginCacheDTO sysUser, ContractExecutePayDetailVO detailVO) {
        // 组装查询条件
        Specification<ApplyAmountOrderDetailDO> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("executeId").as(Long.class), detailVO.getExecuteId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };
        //查询付款明细
        List<ApplyAmountOrderDetailDO> result = repository.findAll(spec);
        List<Long> applyIdList = result.stream().map(ApplyAmountOrderDetailDO::getApplyId).distinct().collect(Collectors.toList());
        List<ApplyAmountOrderDO> applyAmountOrderDOList = orderRepository.findAllById(applyIdList);
        Map<Long, ApplyAmountOrderDO> applyAmountOrderDOMap = applyAmountOrderDOList.stream().collect(Collectors.toMap(ApplyAmountOrderDO::getId, o ->o));
        List<ApplyAmountOrderDetailVO> resultList = result.stream().map(o -> {
            ApplyAmountOrderDetailVO entity = new ApplyAmountOrderDetailVO();
                entity.setApplyAmount(o.getApplyAmount());
                ApplyAmountOrderDO applyAmountOrderDO = applyAmountOrderDOMap.get(o.getApplyId());
                entity.setOrderTime(applyAmountOrderDO.getOrderTime());
                entity.setApplyNo(applyAmountOrderDO.getApplyNo());
                entity.setApplyAbstract(applyAmountOrderDO.getApplyAbstract());
                entity.setStatus(applyAmountOrderDO.getStatus());
                entity.setStatusName(ApplyAmountOrderStatusEnum.getMessage(applyAmountOrderDO.getStatus()));
                //已支付
                if(ApplyAmountOrderStatusEnum.PAY.getCode().equals(applyAmountOrderDO.getStatus())){
                    entity.setPayAmount(o.getApplyAmount());
                    entity.setPayTime(applyAmountOrderDO.getPayTime());
                }
            return entity;
        }).collect(Collectors.toList());
        return Wrapper.success(resultList);
    }

    @Transactional
    @Override
    public void saveList(List<ApplyAmountOrderDetailDO> applyAmountOrderSaveDetailVOS){
        repository.saveAll(applyAmountOrderSaveDetailVOS);
    }
}
